#ifndef POSIXTHEAD_H
#define POSIXTHEAD_H
/*
 * This file is part of the minlog and
 * licensed under the Apache License, version 2
 * http://www.apache.org/licenses/
 *
 * Copyright (c) 2015 rangerlee (rangerlee@foxmail.com)
 * Latest version available at: http://git.oschina.net/rangerlee/minlog.git
 *
 * This project is a simple logger.
 * More information can get from README.md
 *
 */

#include <semaphore.h>
#include <pthread.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sched.h>
#include <string.h>
#include <string>
#include <errno.h>

namespace minlog{
/**
 * \class posixThread
 * \brief 简单封装pthread
 */
class posixThread
{
public:
    posixThread()
    {
        memset(&_thisThread, 0, sizeof(pthread_t));
    }

    virtual ~posixThread()
    {}

    bool start()
    {
        if(alive())
            return false;

        _POSIX_THREAD_STARTUP startup;
        memset(&startup, 0, sizeof(_POSIX_THREAD_STARTUP));
        startup.theThread = this;
        sem_init(&startup.theEvent, 0, 0);
        pthread_attr_t thread_attr;
        int ret = pthread_attr_init(&thread_attr);
        ret = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
        ret = pthread_create(&_thisThread, &thread_attr, threadMain, &startup);
        if(ret)
        {
            return false;
        }

        sem_wait(&startup.theEvent);
        sem_destroy(&startup.theEvent);
        return true;
    }

    void join()
    {
        while(alive())
        {
            int killReturn = pthread_kill(_thisThread,0);
            if(killReturn == ESRCH)
                return;
            else if(killReturn == EINVAL)
                return;
        }
    }

    bool alive()
    {
        if(_thisThread == 0)
            return false;

        if(ESRCH == pthread_kill(_thisThread,0))
        {
            return false;
        }

        return true;
    }

protected:
    virtual void run() = 0;

    struct _POSIX_THREAD_STARTUP
    {
        posixThread* theThread;
        sem_t theEvent;
    };

    static void * threadMain(void * param)
    {
        _POSIX_THREAD_STARTUP* startup = (_POSIX_THREAD_STARTUP*)param;
        posixThread* thread = startup->theThread;
        sem_post(&startup->theEvent);
        int nResult = 0;
        try
        {
            thread->run();
        }
        catch(std::exception& e)
        {
        }
        catch(...)
        {
        }

        return NULL;
    }

private:
    pthread_t _thisThread;
};

}
#endif // LOGTHEAD_H
